//
// Created by HhL on 2020/12/22.
//
#include "com_hhl_jni_thread_MyThread.h"
#include "common.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <assert.h>
//
//JNIEXPORT void JNICALL Java_com_hhl_jni_thread_MyThread_run0(JNIEnv *jEnv, jobject jobj) {
//    JNIEnv env = *jEnv;
//
///* 获取MyThread字节码 */
//    jclass threadClass = env->GetObjectClass(jEnv, jobj);
//    if (NULL == threadClass) {
//        throwRuntimeException(jEnv, "获取线程类字节码失败");
//        return;
//    } else {
//        printf("%s \n", "获取线程类字节码");
//    }
//
///* 获取线程运行函数 */
//    jmethodID runMethod = env->GetMethodID(jEnv, threadClass, "run", "()V");
//    if (NULL == runMethod) {
//        throwRuntimeException(jEnv, "获取线程运行函数失败");
//
//        return;
//    } else {
//        printf("%s \n", "获取线程运行函数run方法");
//    }
//
///* 执行线程运行函数 */
//    env->CallVoidMethod(jEnv, jobj, runMethod);
//}

static JavaVM *jvm = NULL;
static jclass g_threadClass = NULL;

void *thread_fun(void *arg) {
    JNIEnv *jEnv = NULL;
    JNIEnv env = NULL;
    // 将当前线程attach到jvm中，传出JNIEnv  (JavaVM *vm, void **penv, void *args);
    (*jvm)->AttachCurrentThread(jvm, (void **) &jEnv, NULL);
    env = *jEnv;

    /* 获取线程运行函数 */
    jmethodID runMethod = env->GetMethodID(jEnv, g_threadClass, "run", "()V");
    if (NULL == runMethod) {
        throwRuntimeException(jEnv, "获取线程运行函数失败");
        goto return1;
    }
    //实例化线程类
    jobject threadObj = env->AllocObject(jEnv, g_threadClass);
    if (NULL == threadObj) {
        throwRuntimeException(jEnv, "实例化线程对象失败");

        goto return1;
    }
    //执行线程运行函数
    env->CallVoidMethod(jEnv, threadObj, runMethod);
    return1:
    /* 删除注册的全局引用，否则会出现内存泄露 */
    env->DeleteGlobalRef(jEnv, g_threadClass);
    /* 接触attach，否则会出现线程无法退出或不正常退出、jvm会挂等奇葩情况 */
    (*jvm)->DetachCurrentThread(jvm);

    return (void *) 0;
}

JNIEXPORT void JNICALL Java_com_hhl_jni_thread_MyThread_run0(JNIEnv *jEnv, jobject jobj) {
    JNIEnv env = *jEnv;
    pthread_t tid;//操作系统的线程
    /* 获取MyThread字节码 */
    g_threadClass = env->GetObjectClass(jEnv, jobj);
    if (NULL == g_threadClass) {
        throwRuntimeException(jEnv, "获取线程类字节码失败");

        return;
    }
    /* 注册为全局引用，否则其他线程访问不到 */
    env->NewGlobalRef(jEnv, g_threadClass);

    /* 获取jvm */
    env->GetJavaVM(jEnv, &jvm);
    /* 创建OS线程 */
    printf("%s\n","创建OS线程");
    pthread_create(&tid, NULL, thread_fun, NULL);

    /* 测试主线程阻塞，Java线程类MyThread是否会运行 */
    printf("%s\n","睡眠5s");
    sleep(5);
    /* 等待线程运行结束 */
    pthread_join(tid, NULL);
}